package gbench.common.matlib.rdd;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import gbench.common.matlib.MatlibCanvas.IVPair;

/**
 * 对儿值对象 : <br>
 * 可以联想一下 生物化学里面的  含氮碱基 bp,DNA的结构可以理解为PVec结构 <br>
 * 这是一个多维度的键值结构(BasePair)<br>
 *
 * @param <K> 第一位置值 类型
 * @param <V> 第二位置值 类型
 * @author gbench
 */
public class BasePair<K, V> extends IVPair<K, V, BasePair<K, V>> implements IAttrs {

    /**
     * 对儿值对象
     *
     * @param ivp 索引键值对儿
     */
    public <T extends IVPair<K, V, ?>> BasePair(final T ivp) {
        super(ivp.key(), ivp.value());
    }

    /**
     * 对儿值对象
     *
     * @param index 索引，指定编号的维度
     * @param value 值
     */
    public BasePair(final K index, final V value) {
        super(index, value);
    }
    
    /**
     * 对儿值对象
     *
     * @param index 索引，指定编号的维度
     * @param value 值
     * @param attrs 属性集合
     */
    public BasePair(final K index, final V value,Map<? extends Object,? extends Object> attrs) {
        super(index, value);
        this.attrs = new HashMap<>();
        this.attrs.putAll(attrs);
    }

    /**
     * 对儿值对象
     *
     * @param entry Map 的Entry 项目
     */
    public BasePair(final Map.Entry<K, V> entry) {
        super(entry.getKey(), entry.getValue());
    }

    /**
     * 颠倒Key与Value的顺序
     *
     * @return (v, k)的键值对儿
     */
    public BasePair<V, K> swap() {
        return bp(this.value(), this.key());
    }

    /**
     * 值映射 fmap2 的别名
     *
     * @param <U>    值结果变换类型
     * @param mapper 值变换函数
     * @return (K, U) 结构的键值对儿
     */
    public <U> BasePair<K, U> fmap(final Function<V, U> mapper) {
        return this.fmap2(mapper);
    }


    /**
     * 键名映射
     *
     * @param <U>     键结果变换类型
     * @param mapper1 键变换函数:k->u
     * @return (U, V) 结构的键值对儿
     */
    public <U> BasePair<U, V> fmap1(final Function<K, U> mapper1) {
        return new BasePair<>(mapper1.apply(this.key()), this.value());
    }

    /**
     * 值映射
     *
     * @param <U>     值结果变换类型
     * @param mapper2 值变换函数:v->u
     * @return (K, U) 结构的键值对儿
     */
    public <U> BasePair<K, U> fmap2(final Function<V, U> mapper2) {
        return new BasePair<>(this.key(), mapper2.apply(this.value()));
    }

    /**
     * 构造一个 以 (k,v) 为默认元素的 Builder 对象
     * @return 一个 (k,v) 的构建器
     */
    public Builder<BasePair<K,V>> bpb(){
        return BasePair.BPB(this);
    }

    /**
     * 在BasePair前插入一个t元素
     * @param t 前置插入的元素
     * @param <T> t 前置插入元素的类型
     * @return (t,(k,v))
     */
    public <T> BasePair<T,BasePair<K,V>> prepend(final T t){
        return this.bpb().prepend(t);
    }

    /**
     * 在BasePair后插入一个t元素
     * @param t 后置插入的元素
     * @param <T> t 后置插入元素的类型
     * @return ((k,v),t)
     */
    public <T> BasePair<BasePair<K,V>,T> append(final T t){
        return this.bpb().append(t);
    }

    /**
     * 获取属性集合
     */
    @Override
    public Map<Object, Object> getAttributes() {
        if(this.attrs==null) {
            synchronized(this){this.attrs = new HashMap<>();};
        }
        return attrs;
    }

    /**
     * 键值构造器
     * @param <K> 构造器默认值元素类型
     */
    public static class Builder<K> {

        /**
         * 键值构造器
         * @param k 构造器默认元素
         * @return Builder 对象
         */
        public Builder(final K k) {
            this.k = k;
        }

        /**
         * 生成键值对儿 (append的别名)
         * @param <V> 值类型
         * @param v 值对象
         * @return 键值对儿 (k,v)
         */
        public <V> BasePair<K,V> join(final V v){
            return this.append(v);
        }

        /**
         * 生成键值对儿
         * @param <V> 键类型
         * @param v 键对象
         * @return 键值对儿 (v,k)
         */
        public <V> BasePair<V,K> prepend(final V v){
            return BasePair.bp(v,k);
        }

        /**
         * 生成键值对儿
         * @param <V> 值类型
         * @param v 值对象
         * @return 键值对儿 (k,v)
         */
        public <V> BasePair<K,V> append(final V v){
            return BasePair.bp(k,v);
        }

        /**
         * 键值对对儿实例函数
         * @param t 键对象
         * @param u 值对象
         * @param <T> 键类型
         * @param <U> 值类型
         * @return 键值对儿 (t,u)
         */
        public static <T,U> BasePair<T,U> build(final T t, final U u){
            return BasePair.bp(t, u);
        }

        /**
         * 键值对对儿实例函数
         * @param tt 值序列
         * @param <T> 键类型
         * @return 键值对儿 (t,t)
         */
        @SafeVarargs
        public static <T> BasePair<T,T> build(final T ...tt){
            return BasePair.bptt(tt);
        }

        /**
         * 键值对对儿实例函数
         * @param tt 值序列
         * @param <T> 键类型
         * @return 键值对儿 (t,t)
         */
        @SuppressWarnings("unchecked")
        public static <T> BasePair<T,T> build(final Collection<T> tt){
            final var clazz = tt.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findFirst().orElse((Class<T>)Object.class);
            return build(tt.toArray(n->(T[])Array.newInstance(clazz,n)));
        }

        /**
         * 键值对对儿实例函数
         * @param tt 值序列
         * @param <T> 键类型
         * @return 键值对儿 (t,t)
         */
        public static <T> BasePair<T,T> build(final Stream<T> tt){
            return build(tt.collect(Collectors.toList()));
        }

        /**
         * 默认值
         */
        final K k;
    }

    /**
     * 生成一个K类型的 BasePair.Builder KeyValueBuilder(KVB)
     * @param k 默认值对象
     * @param <K> 默认值类型
     * @return BasePair.Builder
     */
    public static <K> Builder<K> BPB(final K k){
        return new Builder<>(k);
    }

    /**
     * 对儿值对象 constructor 构造器,不要重载cons函数,用于lambda的无歧义变换，<br>
     * 比如:ivp.mutate(BasePair::cons)
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @param ivp 键值对儿对象
     * @return (index,value)
     */
    public static <K, V> BasePair<K, V> cons(final IVPair<K, V, ?> ivp) {
        return new BasePair<>(ivp);
    }

    /**
     * Map 元素映射函数<br>
     * 对儿值对象 变换函数
     *
     * @param keyer   键名变换函数
     * @param valueer 键值变换函数
     * @param <T>     元数据键类型
     * @param <U>     新数据值类型
     * @param <K>     结果数据键类型
     * @param <V>     结果数据值类型
     * @return Map 元素映射 函数 e->kvp
     */
    public static <T, U, K, V> Function<Map.Entry<T, U>, BasePair<K, V>> bpf(final Function<T, K> keyer, final Function<U, V> valueer) {
        return entry -> new BasePair<>(keyer.apply(entry.getKey()), valueer.apply(entry.getValue()));
    }

    /**
     * 一般 KVP 键值对儿 映射函数
     * 对儿值对象 变换函数
     *
     * @param keyer   键名变换函数
     * @param valueer 键值变换函数
     * @param <T>     元数据键类型
     * @param <U>     新数据值类型
     * @param <K>     结果数据键类型
     * @param <V>     结果数据值类型
     * @return tup->kvp
     */
    public static <T, U, K, V> Function<BasePair<T, U>, BasePair<K, V>> bpf2(final Function<T, K> keyer, final Function<U, V> valueer) {
        return entry -> new BasePair<>(keyer.apply(entry.key()), valueer.apply(entry.value()));
    }

    /**
     * 对儿值对象
     * 
     * @param <K> 键类型
     * @param <V> 值类型
     * @param index 索引，指定编号的维度
     * @param value 值
     * @return (index,value)
     */
    public static <K, V> BasePair<K, V> bp(final K index, final V value) {
        return new BasePair<>(index, value);
    }
    
    /**
     * 键值对生成
     * 
     * @param tt  元素数组
     * @param <T> 元素类型
     * @return (t0,t1)
     */
    @SafeVarargs
    public static <T> BasePair<T, T> bptt(T... tt) {
        if (tt == null || tt.length < 1) return null;
        final var n = tt.length;
        return new BasePair<>(tt[0 % n], tt[1 % n]);
    }

    /**
     * 对儿值对象kvp 的别名
     *
     * @param index 索引，指定编号的维度
     * @param value 值
     * @return (index,value)
     */
    public static <K, V> BasePair<K, V> BP(final K index, final V value) {
        return bp(index, value);
    }
    
    private Map<Object,Object> attrs; // 属性集合
}